#pragma once

#include <map>
#include "IXDraw.h"

enum ItemStatus
{
    XIS_Normal   = 0,
    XIS_Check    = 1,
    XIS_Enable   = 2,
    XIS_Selected = 3,
};

enum ItemDrawIndex
{
    XID_Normal  = 0,
    XID_Hover   = 1,
    XID_Pressed = 2,
    XID_Disabled= 3,
    XID_Selected= 4,
    XID_Checked = 5,
};

enum ItemColorIndex
{
    XIC_Normal  = 0,
    XIC_Hover   = 1,
    XIC_Selected= 2,
    XIC_Disabled= 3,
};

template < typename T >
class XItemDrawStatus : public T
{
    XItemDrawStatus(const XItemDrawStatus&);
    XItemDrawStatus& operator = (const XItemDrawStatus&);

public:
    XItemDrawStatus()
    {
        ;
    }
    ~XItemDrawStatus()
    {
        ReleaseData();
    }

    virtual HRESULT STDMETHODCALLTYPE   put_Draw(IN IXDraw* pDraw)
    { return SetDraw(XID_Normal, pDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_Draw(OUT IXDraw** ppDraw)
    { return GetDraw(XID_Normal, ppDraw); }

    virtual HRESULT STDMETHODCALLTYPE   put_HoverDraw(IN IXDraw* pHoverDraw)
    { return SetDraw(XID_Hover, pHoverDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_HoverDraw(OUT IXDraw** ppHoverDraw)
    { return GetDraw(XID_Hover, ppHoverDraw); }

    virtual HRESULT STDMETHODCALLTYPE   put_PressDraw(IN IXDraw* pPressDraw)
    { return SetDraw(XID_Pressed, pPressDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_PressDraw(OUT IXDraw** ppPressDraw)
    { return GetDraw(XID_Pressed, ppPressDraw); }

    virtual HRESULT STDMETHODCALLTYPE   put_DisabledDraw(IN IXDraw* pDisabledDraw)
    { return SetDraw(XID_Disabled, pDisabledDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_DisabledDraw(OUT IXDraw** ppDisabledDraw)
    { return GetDraw(XID_Disabled, ppDisabledDraw); }

    virtual HRESULT STDMETHODCALLTYPE   put_SelectedDraw(IN IXDraw* pSelectedDraw)
    { return SetDraw(XID_Selected, pSelectedDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_SelectedDraw(OUT IXDraw** ppSelectedDraw)
    { return GetDraw(XID_Selected, ppSelectedDraw); }

    virtual HRESULT STDMETHODCALLTYPE   put_CheckDraw(IN IXDraw* pCheckDraw)
    { return SetDraw(XID_Checked, pCheckDraw); }
    virtual HRESULT STDMETHODCALLTYPE   get_CheckDraw(OUT IXDraw** ppCheckDraw)
    { return GetDraw(XID_Checked, ppCheckDraw); }

private:

    void ReleaseData()
    {
        DrawMap::iterator Ite = m_DrawMap.begin();
        for(; Ite != m_DrawMap.end(); ++ Ite)
        {
            if(Ite->second != NULL)
                Ite->second->Release();
        }
        m_DrawMap.clear();
    }

    HRESULT SetDraw(ItemDrawIndex index, IXDraw* pDraw)
    {
        DrawMap::iterator ite = m_DrawMap.find(index);
        if(pDraw == NULL)
        {
            if(ite != m_DrawMap.end())
                m_DrawMap.erase(ite);
        }
        else
        {
            if(ite == m_DrawMap.end())
            {
                m_DrawMap.insert(DrawMap::value_type(index, pDraw));
            }
            else
            {
                XSAFE_RELEASE(ite->second);
                ite->second = pDraw;
            }
            pDraw->AddRef();
        }
        IXControl* pControl = dynamic_cast<IXControl*>(this);
        if(pControl != NULL)
            pControl->Invalidate();
        return S_OK;
    }

    HRESULT GetDraw(ItemDrawIndex index, IXDraw** ppResult)
    {
        DrawMap::iterator ite;
        BOOL bContinue = TRUE;
        (*ppResult) = NULL;
        do
        {
            ite = m_DrawMap.find(index);
            if(ite != m_DrawMap.end())
            {
                *ppResult = ite->second;
                bContinue = FALSE;
                break;
            }

            switch(index)
            {
            case XID_Checked:
            case XID_Selected:
            case XID_Pressed:
                index = XID_Hover;
                break;
            case XID_Hover:
            case XID_Disabled:
                index = XID_Normal;
                break;
            default:
                bContinue = FALSE;
                break;
            }
        } while(bContinue);
        if((*ppResult) != NULL)
            (*ppResult)->AddRef();
        return bContinue ? S_OK : E_FAIL;
    }

protected:
    typedef std::map<ItemDrawIndex, IXDraw*> DrawMap;
    DrawMap m_DrawMap;
};

template < typename T >
class XItemColorStatus : public T
{
    XItemColorStatus(const XItemColorStatus&);
    XItemColorStatus& operator = (const XItemColorStatus&);

public:
    XItemColorStatus(){}
    ~XItemColorStatus()
    { ReleaseData(); }

    virtual HRESULT STDMETHODCALLTYPE   put_TextColor(IN COLORREF clrText)
    { return SetColor(XIC_Normal, clrText); }
    virtual HRESULT STDMETHODCALLTYPE   get_TextColor(OUT COLORREF* pClrText)
    { return GetColor(XIC_Normal, pClrText); }

    virtual HRESULT STDMETHODCALLTYPE   put_HoverTextColor(IN COLORREF clrHoverText)
    { return SetColor(XIC_Normal, clrHoverText); }
    virtual HRESULT STDMETHODCALLTYPE   get_HoverTextColor(OUT COLORREF* pClrHoverText)
    { return GetColor(XIC_Normal, pClrHoverText); }

    virtual HRESULT STDMETHODCALLTYPE   put_SelTextColor(IN COLORREF clrSelText)
    { return SetColor(XIC_Normal, clrSelText); }
    virtual HRESULT STDMETHODCALLTYPE   get_SelTextColor(OUT COLORREF* pClrSelText)
    { return GetColor(XIC_Normal, pClrSelText); }

    virtual HRESULT STDMETHODCALLTYPE   put_DisabledTextColor(IN COLORREF clrDisabledText)
    { return SetColor(XIC_Normal, clrDisabledText); }
    virtual HRESULT STDMETHODCALLTYPE   get_DisabledTextColor(OUT COLORREF* pClrDisabledText)
    { return GetColor(XIC_Normal, pClrDisabledText); }

protected:
    void ReleaseData()
    {
        m_ColorMap.clear();
    }

    HRESULT SetColor(ItemColorIndex index, COLORREF clr)
    {
        ColorMap::iterator ite = m_ColorMap.find(index);
        if(ite == m_ColorMap.end())
            m_ColorMap.insert(ColorMap::value_type(index, clr));
        else
            ite->second = clr;
        IXControl* pControl = dynamic_cast<IXControl*>(this);
        if(pControl != NULL)
            pControl->Invalidate();
        return S_OK;
    }

    HRESULT GetColor(ItemColorIndex index, COLORREF* pClr)
    {
        *pClr = RGB(255, 255, 255);
        ColorMap::iterator ite;
        BOOL bContinue = TRUE;
        do
        {
            ite = m_ColorMap.find(index);
            if(ite != m_ColorMap.end())
            {
                *pClr = ite->second;
                bContinue = FALSE;
                break;
            }

            switch(index)
            {
            case XIC_Disabled:
            case XIC_Selected:
            case XIC_Hover:
                index = XIC_Normal;
                break;
            default:
                bContinue = FALSE;
                break;
            }
        } while(bContinue);
        return bContinue ? S_OK : E_FAIL;
    }

protected:
    typedef std::map<ItemColorIndex, COLORREF> ColorMap;
    ColorMap    m_ColorMap;
};

template < typename T >
class ItemDrawColorStatus : public XItemDrawStatus<XItemColorStatus<T>>
{
    typedef XItemDrawStatus<XItemColorStatus<T>> superclass;
    BEGIN_DEF_SKIN_CLASS(ItemDrawColorStatus<T>, superclass, gs_strGuidXSkin)
    END_DEF_SKIN_CLASS();

    ItemDrawColorStatus(const ItemDrawColorStatus&);
    ItemDrawColorStatus& operator = (const ItemDrawColorStatus&);
public:
    ItemDrawColorStatus(){}
};
